import {
  CameraEventType,
  Cartesian3,
  Math as CesiumMath,
  createWorldTerrainAsync,
  defined,
  Viewer,
  Color,
  KeyboardEventModifier,
  Cartesian2,
  GeoJsonDataSource,
  EasingFunction,
  JulianDate,
  SunLight,
  SkyAtmosphere,
  Matrix4,
  HeadingPitchRange,
  WebMapServiceImageryProvider,
  Material,
  MaterialAppearance,
  Rectangle,
  BillboardCollection,
  GroundPrimitive,
  GeometryInstance,
  PolygonGeometry,
  DistanceDisplayCondition,
  HeightReference,
  HorizontalOrigin,
  VerticalOrigin,
  VertexFormat,
  PolygonHierarchy,
  GroundPolylinePrimitive,
  GroundPolylineGeometry,
  NearFarScalar,
  Ellipsoid,
} from 'cesium';
import _ from 'lodash-es';
import proj4 from 'proj4';
import SYQ from '@/assets/images/map-icon/实验区.png';
import HXQ from '@/assets/images/map-icon/核心区.png';
import HCQ from '@/assets/images/map-icon/缓冲区.png';
import { cesiumLayerZIndex } from '@/cesium-utils/js/common-3d-fun';
import {
  addTDT_GOV_Layer,
  CESIUM_MAPBOX_IMG_LAYER,
  CESIUM_TDT_CTA_LAYER,
  CESIUM_TDT_CVA_LAYER,
  CESIUM_TDT_IMG_LAYER,
  CESIUM_TDT_TER_LAYER,
  CESIUM_TDT_VEC_LAYER,
  DEFAULT_MAP_STATE,
} from '@/cesium-utils/js/map-cesium-layer';
import gradientAppearance from './gradientAppearance';

// * 保存地图实例
let map, imageryLayers, imageryLayers_, timer;
let billboardCollection = null; // 用于保存 BillboardCollection 的引用

/**
 * 地图初始化
 * @returns {Viewer}
 */
export async function cesiumMapInit(ID) {
  // RequestScheduler.maximumRequestsPerServer = 18; // 设置cesium请求调度器的最大并发数量
  // RequestScheduler.throttleRequests = false; // 关闭请求调度器的请求节流
  map = new Viewer(ID, {
    homeButton: false, // 主页视角按钮
    animation: false, // 关闭左下角动画组件
    baseLayerPicker: false, // 关闭底图图层切换组件
    geocoder: false, // 关闭搜索定位
    timeline: false, // 时间线部件
    navigationHelpButton: false, // 关闭右上角导航帮助按钮
    navigationInstructionsInitiallyVisible: false, // 不显示提示
    infoBox: false, // 关闭信息框
    selectionIndicator: true, // 关闭选中指示器
    sceneModePicker: false, // 关闭二三维切换
    scene3DOnly: true, // 只渲染 3D，节省资源
    skyAtmosphere: false, // 关闭大气
    shadows: true, // 开启阴影
    shouldAnimate: true, // 开启动画
    fullscreenButton: false, // 全屏按钮
  });

  const terrainProvider = await createWorldTerrainAsync({
    requestWaterMask: true,
    requestVertexNormals: true,
    // heightmapTerrainQuality: 2,
  });

  // const terrainProvider = await Cesium.CesiumTerrainProvider.fromUrl('http://192.168.2.26:8080', {
  //   requestWaterMask: true,
  //   requestVertexNormals: true,
  //   ellipsoid: Ellipsoid.WGS84,
  //   // heightmapTerrainQuality: 2,
  // });

  map.terrainProvider = terrainProvider;

  // * 调整鼠标习惯
  map.scene.screenSpaceCameraController.zoomEventTypes = [CameraEventType.WHEEL, CameraEventType.PINCH];
  map.scene.screenSpaceCameraController.tiltEventTypes = [
    CameraEventType.PINCH,
    CameraEventType.RIGHT_DRAG,
    {
      eventType: CameraEventType.RIGHT_DRAG,
      modifier: KeyboardEventModifier.CTRL,
    },
  ];
  // 开启深度检测
  map.scene.globe.depthTestAgainstTerrain = true;
  // 设置球体背景色
  map.scene.globe.baseColor = new Color(0, 0, 0, 0);

  // 设置最大最小缩放限制
  map.scene.screenSpaceCameraController.maximumZoomDistance = 20000000;
  // 地形夸大
  // map.scene.verticalExaggeration = 2.0;

  // 隐藏品牌标识
  document.getElementsByClassName('cesium-widget-credits')[0].style.display = 'none';
  // 抗锯齿
  map.scene.postProcessStages.fxaa.enabled = true;
  // map.scene.globe.enableLighting = true; //关闭光照
  map.shadows = false; //关闭阴影
  map.scene.light = new SunLight(); // 添加太阳光源
  map.scene.skyAtmosphere = new SkyAtmosphere();
  map.clockViewModel.currentTime = JulianDate.fromDate(new Date('2023-10-01T12:00:00'));
  map.scene.sun.show = false; //还可以viewer.scene.sun.destroy();
  map.scene.moon.show = false;

  // 添加4490解析
  GeoJsonDataSource.crsNames['urn:ogc:def:crs:EPSG::4490'] = (coordinates) => {
    const fromProjection = `GEOGCS["China Geodetic Coordinate System 2000",DATUM["China_2000",SPHEROID["CGCS2000",6378137,298.257222101,AUTHORITY["EPSG","1024"]],AUTHORITY["EPSG","1043"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4490"]]`;

    const toProjection = `GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]]`;

    const x = coordinates[0];
    const y = coordinates[1];

    const newCoordinates = proj4(fromProjection, toProjection, [x, y]);

    return Cartesian3.fromDegrees(newCoordinates[0], newCoordinates[1], 0);
  };

  flyToHome('init', map);

  ChangeBaseLayer('0.8m遥感影像');

  return map;
}

/**
 * 底图切换
 */
export function ChangeBaseLayer(layerName) {
  imageryLayers && map.imageryLayers.remove(imageryLayers);
  imageryLayers_ && map.imageryLayers.remove(imageryLayers_);

  switch (layerName) {
    case '底图':
      imageryLayers = addTDT_GOV_Layer(map);
      break;

    case '影像图':
      imageryLayers = map.imageryLayers.addImageryProvider(CESIUM_TDT_IMG_LAYER, cesiumLayerZIndex['影像图层']);
      imageryLayers_ = map.imageryLayers.addImageryProvider(CESIUM_TDT_CVA_LAYER, cesiumLayerZIndex['影像图层']);
      break;

    case '道路图':
      imageryLayers = map.imageryLayers.addImageryProvider(CESIUM_TDT_VEC_LAYER, cesiumLayerZIndex['影像图层']);
      imageryLayers_ = map.imageryLayers.addImageryProvider(CESIUM_TDT_CVA_LAYER, cesiumLayerZIndex['矢量标记图层']);
      break;

    case '地形晕染图':
      imageryLayers = map.imageryLayers.addImageryProvider(CESIUM_TDT_TER_LAYER, cesiumLayerZIndex['地形晕染图层']);
      imageryLayers_ = map.imageryLayers.addImageryProvider(
        CESIUM_TDT_CTA_LAYER,
        cesiumLayerZIndex['地形晕染标记图层'],
      );
      break;

    case 'MapBox底图':
      imageryLayers = map.imageryLayers.addImageryProvider(CESIUM_MAPBOX_IMG_LAYER, cesiumLayerZIndex['影像图层']);
      break;
  }
}

/**
 * 初始化地图视角
 */
export function flyToHome(type, map = map, cb) {
  if (!map) return;

  if (type === 'init') {
    map.camera.flyTo({
      destination: Cartesian3.fromDegrees(103.84, 31.15, 16000000),
      orientation: {
        heading: CesiumMath.toRadians(348.4202942851978),
        pitch: CesiumMath.toRadians(-89.74026687972041),
        roll: CesiumMath.toRadians(0),
      },
      complete: function callback() {
        cb && cb();
      },
    });
  } else {
    const target = Cartesian3.fromDegrees(DEFAULT_MAP_STATE.longitude, DEFAULT_MAP_STATE.latitude, 220000); // 经度、纬度、高度（单位：米）
    const offset = new HeadingPitchRange(
      CesiumMath.toRadians(0), // 设置朝向角度
      CesiumMath.toRadians(-30), // 设置俯仰角
      220000, // 距离目标点的距离
    );

    map.camera.lookAt(target, offset);
    map.camera.lookAtTransform(Matrix4.IDENTITY);
  }
}

/**
 * 返回3d地图实例0
 * @export
 * @returns {Map}
 */
export function getCesiumMap() {
  return map;
}

/**
 *
 * 销毁cesium
 */
export function destroyCesiumViewer(viewer) {
  if (!defined(viewer)) return;

  try {
    // 1. 移除所有图层
    viewer.entities.removeAll();
    viewer.imageryLayers.removeAll();
    viewer.dataSources.removeAll();

    // 2. 销毁 Viewer
    viewer.destroy();
  } catch (error) {
    console.error('Error destroying Cesium viewer:', error);
  }
}

/**
 *  获取当前 相机参数
 *
 * @export
 * @param {*} map
 * @return {{
 * position:  Cartesian3,
 * cameraPos:  Cartesian3,
 * }}
 */
export function getCameraPosition(map) {
  const { heading, pitch, roll, _position } = map.camera;
  const obj = {
    destination: _.cloneDeep(_position),
    orientation: {
      heading,
      pitch,
      roll,
    },
  };

  const ellipsoid = Ellipsoid.WGS84; // 使用 WGS84 椭球体模型
  const cartographic = ellipsoid.cartesianToCartographic(_position);
  const longitude = CesiumMath.toDegrees(cartographic.longitude);
  const latitude = CesiumMath.toDegrees(cartographic.latitude);
  const height = cartographic.height;
  const _obj = {
    destination: `[${longitude},${latitude},${height}]`,
    orientation: {
      heading: CesiumMath.toDegrees(heading),
      pitch: CesiumMath.toDegrees(pitch),
      roll: CesiumMath.toDegrees(roll),
    },
  };

  console.info(
    '\n-------------------开始-------------------------\n',
    // ' map.camera\t',
    // map.camera,
    'heading:',
    CesiumMath.toDegrees(heading),
    '\n------------------------------------------------\n',
    '\npitch:\n',
    CesiumMath.toDegrees(pitch),
    '\n------------------------------------------------\n',
    '\nroll:\n',
    CesiumMath.toDegrees(roll),

    '\n------------------------------------------------\n',
    '\n_position\n',
    _position,
    '\n------------------------------------------------\n',
    '\n相机位置集合\n',
    window._list,
    '\n------------------------------------------------\n',
    '\n相机位置数据是转换过后的可直接用\n',
    obj,
    '\n------------------------------------------------\n',
    '\n相机位置数据没有转换过的原始数据\n',
    _obj,
    '\n-------------------结束-------------------------\n',
  );

  // return {
  //   position:_position,
  //   camera:_obj
  // } ;
  return _obj;
}

/**
 * 移除图层
 */
export const CESIUM_REMOVE_LAYER = (layer) => {
  if (layer) {
    map?.imageryLayers?.remove(layer);
  }
};

//----------------------------------------------首页动画-------------------------------------------------------
const pointListMap = new Map(); // 所有实体点
const polygonListMap = new Map(); // 所有面
const polylineListMap = new Map(); // 所有线
let primitiveMap = new Map();
let ti;

/**
 *相机沿路径匀速运动
 *
 * @export
 * @param { *     {
 *       destination: {
 *         x: -1744331.2749499872,
 *         y: 4978373.107470465,
 *         z: 3576473.597760516,
 *       },
 *       heading: 5.194075039630026,
 *       pitch: -0.4007239237451212,
 *       roll: 0.000013133457694713968,
 *     },} list
 */
export function cameraPath(
  list = [
    {
      destination: {
        x: -1744331.2749499872,
        y: 4978373.107470465,
        z: 3576473.597760516,
      },
      heading: 5.194075039630026,
      pitch: -0.4007239237451212,
      roll: 0.000013133457694713968,
      duration: 10,
    },
    {
      destination: {
        x: -1735070.3092046254,
        y: 4979612.08053496,
        z: 3579252.483262195,
      },
      heading: 5.194075527570741,
      pitch: -0.40072332165351576,
      roll: 0.000011882599418200357,
      easingFunction: EasingFunction.LINEAR_NONE,
      duration: 10,
    },
  ],
  cb,
) {
  // const defaultEase = Cesium.EasingFunction.QUADRATIC_IN_OUT;

  const defaultEase = EasingFunction.SINUSOIDAL_IN_OUT; // 更柔和的进出

  const defaultDuration = 60;

  loop(list);

  function loop(arr) {
    const { destination, heading, pitch, roll, duration = defaultDuration, easingFunction = defaultEase } = arr.shift();

    map.camera.flyTo({
      destination: destination,
      orientation: {
        heading: heading,
        pitch: pitch,
        roll: roll,
      },
      complete: function callback() {
        arr.length;

        if (arr.length) {
          loop(arr);
        } else {
          cb && cb();
        }
      },
      easingFunction: easingFunction,
      duration: duration ?? 6,
    });
  }
}

/**
 * 添加图层
 */
export const CESIUM_ADD_LAYER = (layerName, styles) => {
  if (!map) return;

  const newLayer = new WebMapServiceImageryProvider({
    //创建一个图层（geoServer中的tif）
    url: `${import.meta.env.VITE_BASE_GEO_SERVER_URL}/wms`, // geoServer服务地址
    layers: layerName, // 工作区名：图层名
    parameters: {
      service: 'WMS',
      format: 'image/png',
      srs: 'EPSG:4326', // 坐标系
      transparent: true,
      styles: styles,
      TILED: true,
      buffer: 200,
      // CQL_FILTER:"Layer" = '核心区'
    },
  });

  return map.imageryLayers.addImageryProvider(newLayer);
};

/**
 * 添加保护区标注图标
 */

let billboardList = [];

export const CESIUM_ADD_PROTECT_LABEL = () => {
  let viewer = map;
  const labels = [
    { position: Cartesian3.fromDegrees(105.91849457, 38.83605148), label: '核心区' },
    { position: Cartesian3.fromDegrees(105.86623315, 38.91548597), label: '缓冲区' },
    { position: Cartesian3.fromDegrees(105.97573327, 39.03737075), label: '实验区' },
    { position: Cartesian3.fromDegrees(105.82143765, 38.54468153), label: '实验区' },
  ];

  billboardCollection = new BillboardCollection({ scene: viewer.scene });

  viewer.scene.primitives.add(billboardCollection);

  // 一次性展示所有图标
  labels.forEach((item) => {
    let iconPath = '';

    switch (item.label) {
      case '核心区':
        iconPath = HXQ;
        break;

      case '缓冲区':
        iconPath = HCQ;
        break;

      case '实验区':
        iconPath = SYQ;
        break;

      default:
        iconPath = SYQ;
    }

    const billboard = billboardCollection.add({
      position: item.position,
      image: iconPath,
      scale: 1.5,
      distanceDisplayCondition: new DistanceDisplayCondition(0, 9000000),
      scaleByDistance: new NearFarScalar(50000, 1, 500000, 0.5),
      pixelOffset: new Cartesian2(0, -20),
      heightReference: HeightReference.CLAMP_TO_GROUND,
      horizontalOrigin: HorizontalOrigin.CENTER,
      verticalOrigin: VerticalOrigin.BOTTOM,
    });

    billboardList.push({ billboard });
  });
};

export const CESIUM_REMOVE_PROTECT_LABEL = () => {
  if (billboardCollection) {
    billboardCollection.removeAll(); // 移除所有图标
    billboardCollection = null; // 清空引用
  }

  billboardList = []; // 清空列表
};

/**
 * 添加区域标注
 */
let arealabelList = [];

export const CESIUM_ADD_REGION_LABEL = (map, json, cb = () => {}) => {
  const labels = [
    { position: Cartesian3.fromDegrees(105.91849457, 38.83605148), label: '核心区' },
    { position: Cartesian3.fromDegrees(105.86623315, 38.91548597), label: '缓冲区' },
    { position: Cartesian3.fromDegrees(105.97573327, 39.03737075), label: '实验区' },
    { position: Cartesian3.fromDegrees(105.82143765, 38.54468153), label: '实验区' },
  ];

  let viewer = map;

  const coords = processCoordinates(json);

  // 绑定 feature 数据与坐标
  const regions = json.features.map((feature, i) => ({
    type: feature.properties.name || guessRegionType(coords[i]),
    coords: coords[i],
    label: labels[i] || null,
  }));

  // 分组
  const groupedRegions = {
    实验区: [],
    缓冲区: [],
    核心区: [],
  };

  regions.forEach((region) => {
    groupedRegions[region.type].push(region);
  });

  const displayOrder = [
    { type: '实验区', color: Color.fromCssColorString('#00FFDE') },
    { type: '缓冲区', color: Color.fromCssColorString('#FFE24E') },
    { type: '核心区', color: Color.fromCssColorString('#FF6161') },
  ];

  billboardCollection = new BillboardCollection({ scene: viewer.scene });

  viewer.scene.primitives.add(billboardCollection);

  // 控制显示函数
  let step = 0;
  const interval = 1500; // 每隔 1 秒显示一组

  const showNextGroup = () => {
    if (step >= displayOrder.length) return;

    const group = displayOrder[step];
    const items = groupedRegions[group.type];

    // 同时添加该组的所有项
    items.forEach((item) => {
      const polygon = viewer.scene.primitives.add(
        new GroundPrimitive({
          geometryInstances: new GeometryInstance({
            geometry: new PolygonGeometry({
              polygonHierarchy: new PolygonHierarchy(item.coords),
              vertexFormat: VertexFormat.ALL,
            }),
          }),
          appearance: gradientAppearance(group.color.withAlpha(0.3)),
        }),
      );

      const polyline = viewer.scene.primitives.add(
        new GroundPolylinePrimitive({
          geometryInstances: new GeometryInstance({
            geometry: new GroundPolylineGeometry({
              positions: item.coords,
              width: 10,
            }),
          }),
          appearance: new MaterialAppearance({
            material: new Material({
              fabric: {
                // type: 'PolylineDash',
                type: 'PolylineGlow', //Color 实线  PolylineDash 虚线  PolylineGlow 发光线
                uniforms: {
                  // color: group.color,
                  color: Color.fromCssColorString('#00ffde'),
                },
              },
            }),
          }),
        }),
      );

      if (item.label) {
        let iconPath = '';

        switch (item.type) {
          case '核心区':
            iconPath = HXQ;
            break;

          case '缓冲区':
            iconPath = HCQ;
            break;

          case '实验区':
            iconPath = SYQ;
            break;

          default:
            iconPath = SYQ;
        }

        const billboard = BillboardCollection.add({
          position: item.label.position,
          image: iconPath,
          scale: 1.5,
          distanceDisplayCondition: new DistanceDisplayCondition(0, 9000000),
          scaleByDistance: new NearFarScalar(50000, 1, 500000, 0.5),
          pixelOffset: new Cartesian2(0, -20),
          heightReference: HeightReference.CLAMP_TO_GROUND,
          horizontalOrigin: HorizontalOrigin.CENTER,
          verticalOrigin: VerticalOrigin.BOTTOM,
        });

        arealabelList.push({ billboard, polyline, polygon });
      } else {
        arealabelList.push({ polyline, polygon });
      }
    });

    step++;
  };

  // 启动定时器
  timer = setInterval(() => {
    showNextGroup();
    if (step >= displayOrder.length) clearInterval(timer);
  }, interval);

  cb && cb();
};

//! 处理坐标函数（保持不变）
function processCoordinates(json) {
  const jsonCartesian3S = [];

  json.features.forEach((v) => {
    const coords = v.geometry.coordinates.flat(2);

    jsonCartesian3S.push(Cartesian3.fromDegreesArray(coords));
  });

  return jsonCartesian3S;
}

//! 可选：根据坐标猜测区域类型（如果 geojson 中没有 type 字段）
function guessRegionType(coords) {
  const center = Rectangle.center(Rectangle.fromCartesianArray(coords));
  const longitude = CesiumMath.toDegrees(center.longitude);
  const latitude = CesiumMath.toDegrees(center.latitude);

  // 示例逻辑：根据坐标范围判断
  if (latitude > 38.9 && longitude < 106) return '核心区';
  if (latitude > 38.8 && latitude < 39) return '缓冲区';

  return '实验区';
}

/**
 *清除所有dataSources
 *
 * @export
 * @param {*} [reserve=[]] 保留的名字数组
 */
export function CLEAR_MAP_DATA_SOURCES(reserve = []) {
  var dataSources = map.dataSources;

  var dataSourceArray = dataSources._dataSources;

  if (reserve.length) {
    for (let i = dataSourceArray.length - 1; i >= 0; --i) {
      let dataSource = dataSourceArray[i];

      // 根据特定的条件判断是否删除该数据源
      if (/* 满足删除条件 */ !reserve.includes(dataSource.name)) {
        dataSources.remove(dataSource);

        if (dataSource.name) {
          pointListMap.forEach((item, key) => {
            item.fid == dataSource.name && pointListMap.delete(key);
          });
          polygonListMap.forEach((item, key) => {
            item.fid == dataSource.name && polygonListMap.delete(key);
          });
          polylineListMap.forEach((item, key) => {
            item.fid == dataSource.name && polylineListMap.delete(key);
          });
        }
      }
    }
  } else {
    for (let i = 0; i < dataSourceArray.length; i++) {
      let dataSource = dataSourceArray[i];

      if (dataSource.name) {
        pointListMap.forEach((item, key) => {
          item.fid == dataSource.name && pointListMap.delete(key);
        });
        polygonListMap.forEach((item, key) => {
          item.fid == dataSource.name && polygonListMap.delete(key);
        });
        polylineListMap.forEach((item, key) => {
          item.fid == dataSource.name && polylineListMap.delete(key);
        });
      }
    }

    map.dataSources.removeAll(true);
  }
}

export function CLEAR_MAP_ENTITIES(reserve = []) {
  if (!map) return;

  if (reserve?.length) {
    // 清空除需要保留外 的 实体对象
    var entities = map?.entities?.values;

    for (var i = entities?.length - 1; i >= 0; --i) {
      var entity = entities[i];

      if (reserve?.includes(entity?._id)) {
        map?.entities?.remove(entity);
      }
    }
  } else {
    // 清空实体对象数组
    map?.entities?.removeAll();
  }
}

/**
 * 清空primitives中的图层
 * @param {*} [reserve=[]] 保留primitives 的key的数组 ！ps primitives本身是不提供key 或者 id 来识别是哪一个primitives。 这里采用了Map手动记录
 */
export function CLEAR_MAP_PRIMITIVES(reserve = []) {
  // 遍历删除所有primitives

  primitiveMap.forEach(function (primitive, key) {
    if (!reserve.includes(key)) {
      map.scene.primitives.remove(primitive);
      primitiveMap.delete(key);
    }
  });

  ti && clearInterval(ti);

  // 这里不能直接removeAll。 他会导致DataSource 无法成功删除
  // map.scene.primitives.removeAll();
}

export const clearArealabelList = () => {
  let viewer = map;

  // 遍历 arealabelList 移除所有添加的图元
  arealabelList.forEach(({ billboard, polyline, polygon }) => {
    if (billboard && viewer.scene.primitives.contains(billboardCollection)) {
      billboardCollection.remove(billboard);
    }

    if (polyline && viewer.scene.primitives.contains(polyline)) {
      viewer.scene.primitives.remove(polyline);
    }

    if (polygon && viewer.scene.primitives.contains(polygon)) {
      viewer.scene.primitives.remove(polygon);
    }
  });

  // 清空数组和定时器
  arealabelList = [];

  if (timer) {
    clearInterval(timer);
    timer = null;
  }
};
